package org.august.uid.transport;

import java.util.concurrent.TimeUnit;

import org.august.uid.common.Constants;
import org.august.uid.config.SocketConfig;
import org.august.uid.kryo.KryoDecoder;
import org.august.uid.kryo.KryoEncoder;
import org.august.uid.transport.handler.HeartBeatHandler;
import org.august.uid.transport.handler.PackageResolveHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.concurrent.DefaultThreadFactory;

@Component
public class NettyServer {
	
	private static final Logger logger = LoggerFactory.getLogger(NettyServer.class);
	
	@Autowired
	private SocketConfig socketConfig;
	@Autowired
	private PackageResolveHandler packageResolveHandler;
	@Autowired
	private HeartBeatHandler heartBeatHandler;
	
	public void start() {
		new Thread(new Runnable() {
			@Override
			public void run() {
				init();
			}
		}).start();
	}
	
	public void init() {
		
		ServerBootstrap serverBootstrap = new ServerBootstrap();
		
		EventLoopGroup bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("NettyServerBoss", true));
		EventLoopGroup workerGroup = new NioEventLoopGroup(Constants.DEFAULT_IO_THREADS,new DefaultThreadFactory("NettyServerWorker", true));
		
		try {
			
			serverBootstrap.group(bossGroup, workerGroup)
						   .channel(NioServerSocketChannel.class)
						   .handler(new LoggingHandler(LogLevel.DEBUG))
						   .option(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
						   .option(ChannelOption.SO_BACKLOG, 1024)//连接数
						   .option(ChannelOption.TCP_NODELAY, Boolean.TRUE);//不延迟，消息立即发送
			
			serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
	
				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					ChannelPipeline p = ch.pipeline();
	                p.addLast(new KryoDecoder());
	                p.addLast(new KryoEncoder());
	                p.addLast(heartBeatHandler);
	                p.addLast(packageResolveHandler);
				}
				
			});
			ChannelFuture channelFuture = serverBootstrap.bind(socketConfig.getPort()).sync();
			if(channelFuture.isSuccess()) {
				logger.info("Socket started on port(s): {}",socketConfig.getPort());
			}
			channelFuture.channel().closeFuture().sync();
		}catch(Exception e) {
			logger.error(e.getMessage(),e);
		}finally {
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}
	
}
